package edu.gmu.streams;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;

/**
 * A StreamInputStream read primitive Java numbers
 * and characters to an input stream in a indicated endian format.
 * <p>
 * This class uses the traditional stream approach instead of block approach.
 *
 * @author  James H. Pope
 * @version $Revision:$ $Date:$
 */
public class StreamInputStream implements BlockInputStream
{
    //private int read = 0;
    private DataInputStream in = null;
    
    /**
     * Creates a new StreamInputStream and chains it to the input
     * stream specified by the in argument.
     * @param in
     */
    public StreamInputStream( ByteArrayInputStream in )
    {
        this.in = new DataInputStream(in);
    }
    
    /**
     * Skips the number of bytes ahead as indicated.
     * @param num bytes to skip
     */
    public void skipBytes(int skip) throws IOException
    {
        // Not so efficient - but gets the job done
        for (int i = 0; i < skip; i++)
        {
            this.in.read(); // ignore return, move position by one
        }
    }
    
    /**
     * Reads byte from underlying stream.
     * @return b
     * @throws java.io.IOException
     */
    public byte readByte() throws IOException
    {
        return (byte)this.in.read();
    }
    
    /**
     * Reads boolean (1-byte) from underlying stream.
     * @return
     * @throws java.io.IOException
     */
    public boolean readBoolean() throws IOException
    {
        return this.in.readBoolean();
    }
    
    /**
     * Reads the next two bytes from underlying stream as an short.
     * @return short
     * @throws java.io.IOException
     */
    public short readShort() throws IOException
    {
        return this.in.readShort();
    }
    
    /**
     * Reads the next four bytes from underlying stream as an int.
     * @return int
     * @throws java.io.IOException
     */
    public int readInt() throws IOException
    {
        return this.in.readInt();
    }
    
    /**
     * Reads the next eight bytes from underlying stream as a long.
     * @return long
     * @throws java.io.IOException
     */
    public long readLong() throws IOException
    {
        return this.in.readLong();
    }
    
    /**
     * Reads the next four bytes from underlying stream as a float.
     * @return float
     * @throws java.io.IOException
     */
    public float readFloat() throws IOException
    {
        return this.in.readFloat();
    }
    
    /**
     * Reads the next eight bytes from underlying stream as a double.
     * @return double
     * @throws java.io.IOException
     */
    public double readDouble() throws IOException
    {
        return this.in.readDouble();
    }
    
    /**
     * Reads variable length (2-byte length header) of UTF characters from
     * the underlying stream as a String. 
     * @return String
     * @throws java.io.IOException
     */
    public String readUTF() throws IOException
    {
        return this.in.readUTF();
    }
    
    
    /**
     * Bulk transfers bytes from this buffer into the given destination array.
     * @param bytes
     * @throws java.io.IOException
     */
    public void read( byte[] bytes ) throws IOException
    {
        this.in.read(bytes);
    }
    
    /**
     * Bulk transfers bools from this buffer into the given destination array.
     * Implemenations may fall back to loop-calling readBoolean().
     * @param booleans
     * @throws java.io.IOException
     */
    public void read( boolean[] booleans ) throws IOException
    {
        for (int i = 0; i < booleans.length; i++)
        {
            booleans[i] = this.readBoolean();
        }
    }
    
    /**
     * Bulk transfers shorts from this buffer into the given destination array.
     * @param shorts
     * @throws java.io.IOException
     */
    public void read( short[] shorts ) throws IOException
    {
        for (int i = 0; i < shorts.length; i++)
        {
            shorts[i] = this.readShort();
        }
    }
    
    /**
     * Bulk transfers ints from this buffer into the given destination array.
     * @param integers
     * @throws java.io.IOException
     */
    public void read( int[] integers ) throws IOException
    {
        for (int i = 0; i < integers.length; i++)
        {
            integers[i] = this.readInt();
        }
    }
  
    /**
     * Bulk transfers floats from this buffer into the given destination array.
     * @param floats
     * @throws java.io.IOException
     */
    public void read( float[] floats ) throws IOException
    {
        for (int i = 0; i < floats.length; i++)
        {
            floats[i] = this.readFloat();
        }
    }
    
    /**
     * Bulk transfers longs from this buffer into the given destination array.
     * @param longs
     * @throws java.io.IOException
     */
    public void read( long[] longs ) throws IOException
    {
        for (int i = 0; i < longs.length; i++)
        {
            longs[i] = this.readLong();
        }
    }
    
    /**
     * Bulk transfers doubles from this buffer into the given destination array.
     * @param doubles
     * @throws java.io.IOException
     */
    public void read( double[] doubles ) throws IOException
    {
        for (int i = 0; i < doubles.length; i++)
        {
            doubles[i] = this.readDouble();
        }
    }
    
    /**
     * Bulk transfers String from this buffer into the given destination array.
     * Implemenations may fall back to looping-calling readUTF().
     * @param strings
     * @throws java.io.IOException
     */
    public void read( String[] strings ) throws IOException
    {
        for (int i = 0; i < strings.length; i++)
        {
            strings[i] = this.in.readUTF();
        }
    }


} //end ByteBufferInputStream
